﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Data.SqlClient;
using System.Runtime.InteropServices;

namespace binary
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        string tabela, plik;

        public delegate void Proces();
        public delegate void Proces2(string tekst);
        public delegate void ProcesInt(int wartosc);
        public DataTable dane = new DataTable();
        public int zaladowano = 0, liczba = 0;
        public bool ReadActive = false; 
        public bool WriteActive = false;
        public PolaczenieSql p;
        public DataTable nowe_dane = new DataTable();
        public Thread ThreadRead, ThreadWrite, ThreadProgress, ThreadAutomat,Thread_Kontroler;
        public MyDBF dbf = null;
        public DateTime start, stop, start_calkowity;
        public DataTable ListaTabel;
        public string TrybPracy; // przyjmuje wartości 'single' lub 'multi'
        public List<MyBlad> ListaBledow = new List<MyBlad>();
        public List<string> tabele = new List<string>();


        private void Form1_Load(object sender, EventArgs e)
        {
            // pobieramy listę tabel do załadowania  
            getListaTabel(); 
            // wpisujemy folder z którego mamy pobierać dane
            MyWidok.setInputValue(inputFolder,getParametr("folder_dbf"));
        }

        private void btSingleStart_Click(object sender, EventArgs e)
        { this.TrybPracy = "single"; Start(); }

        private void btMultiStart_Click(object sender, EventArgs e)
        { this.TrybPracy = "multi"; Start(); }

        private void Start()
        {
            Thread_Kontroler = new Thread(new ThreadStart(new Proces(Kontroler)));
            Thread_Kontroler.Start(); // startujemy wątek sprawdzający pojawianie się błędów
            start = DateTime.Now; start_calkowity = DateTime.Now;
            this.zaladowano = 0; this.liczba = 0;
            this.p = new PolaczenieSql(inputSerwer.Text, inputNazwaBazy.Text);
            if (p._polaczenie.State == ConnectionState.Open)
            {
                if (this.TrybPracy == "multi") 
                {
                    ThreadAutomat = new Thread(new ThreadStart(new Proces(PetlaAutomat)));
                    ThreadAutomat.Start();
                }
                if (this.TrybPracy == "single") { LadujSingle(); }
            }
            else
            { MessageBox.Show("Nie można nawiązać połączenia"); }
        }

        private void LadujSingle()
        {
            tabela = inputNazwaTabeli.Text;
            if (inputPlik.Text.Length > 0)
            {
                WriteActive = true; ReadActive = true;
                ThreadRead = new Thread(new ThreadStart(new Proces(Read)));
                ThreadRead.Start();
                ThreadWrite = new Thread(new ThreadStart(new Proces(Write)));
                ThreadWrite.Start();
            }
            else
            { MessageBox.Show("Nie wybrałeś pliku źródłowego!"); }
        }



        public void PetlaAutomat()
        {
            int i = 0;
            foreach (DataRow r in this.ListaTabel.Rows)
            {
                while (this.ReadActive || this.WriteActive)
                { Thread.Sleep(1000); } // zatrzymaj jeżeli trwa ładowanie i zaczekaj
                this.plik = r["nazwa"].ToString() + ".dbf";
                this.Invoke(new ProcesInt(setPodswietlTabele), i);
                string nazwaTabeli = r["nazwa"].ToString();
                if (File.Exists(String.Format("{0}\\{1}.dbf", inputFolder.Text, nazwaTabeli)))
                {
                    this.Invoke(new Proces2(LadujAutomat), nazwaTabeli);
                }
                else
                {
                    this.ListaBledow.Add(new MyBlad(nazwaTabeli, "-", 0, "nie odnaleziono pliku"));
                }
                i++;
            }
            while (this.ReadActive || this.WriteActive)
            {
                Thread.Sleep(1000);
            }
            gridListaTabel.Rows[gridListaTabel.Rows.Count - 2].DefaultCellStyle.BackColor = Color.White;
            MessageBox.Show("Ładowanie w trybie Multi zakończone.");
        }

        private void LadujAutomat(string tabela_in)
        {
            this.tabela = tabela_in;
            WriteActive = true; ReadActive = true;
            ThreadRead = new Thread(new ThreadStart(new Proces(Read)));
            ThreadRead.Start();
            ThreadWrite = new Thread(new ThreadStart(new Proces(Write)));
            ThreadWrite.Start();
        }

        private void Read()
        {
            try
            {                
                bool StartReading = false;
                if (this.TrybPracy == "single")
                {
                    if (File.Exists(@inputPlik.Text))
                    {
                        this.dbf = new MyDBF(@inputPlik.Text, Path.GetFileNameWithoutExtension(inputPlik.Text));
                        StartReading = true;
                        ThreadProgress = new Thread(new ThreadStart(new Proces(WatekProgressu)));
                        ThreadProgress.Start();
                    }
                    else
                        throw new Exception("Nie znaleziono pliku");
                }
                else if (this.TrybPracy == "multi")
                {
                    string lokalizacja = inputFolder.Text + "\\" + this.plik;
                    if (File.Exists(lokalizacja))
                    {
                        this.dbf = new MyDBF(lokalizacja, Path.GetFileNameWithoutExtension(lokalizacja));
                        StartReading = true;
                        ThreadProgress = new Thread(new ThreadStart(new Proces(WatekProgressu)));
                        ThreadProgress.Start();
                    }
                    else
                    {
                        this.ListaBledow.Add(new MyBlad(this.plik, "", 0, "Nie znaleziono pliku"));
                        throw new Exception("Nie znaleziono pliku: " + lokalizacja);
                    }      
                }
                if (StartReading)
                {
                    this.p.ZapytajVoid(SqlWorker.getPola(dbf.Kolumny, this.tabela));
                    this.dbf.PobierzDane(dane);   
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            ReadActive = false;
        }

        private void Write()
        {
            while (this.ReadActive || this.dane.Rows.Count > 0)
            {
                if (this.dane.Rows.Count > 0)
                {
                    Monitor.Enter(this.dane);
                        this.liczba += this.dane.Rows.Count;
                        this.nowe_dane = this.dane.Copy();
                        this.dane.Rows.Clear();
                        GC.Collect();
                    Monitor.Exit(this.dane);
                    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(p._polaczenie))
                    {
                        bulkCopy.BulkCopyTimeout = 999999999;
                        bulkCopy.DestinationTableName = this.tabela;
                        try
                        {
                            bulkCopy.WriteToServer(nowe_dane);
                            zaladowano = zaladowano + nowe_dane.Rows.Count;
                            nowe_dane = null;
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("Bulk: " + ex.Message);
                        }
                        bulkCopy.Close();
                    }
                }
            }
            stop = DateTime.Now;
            WriteActive = false;
        }

        private void Kontroler()
        {
            while (true)
            {
                Thread.Sleep(500);
                if (this.dbf != null)
                {
                    if (this.dbf.ListaBledy.Count > 0) { Invoke(new Proces(UpdateLog)); }
                }
            }
        }

        private void UpdateLog()
        {
            if (this.dbf != null)
            {
                for (int i = 0; i < this.dbf.ListaBledy.Count; i++)
                    { this.ListaBledow.Add(dbf.ListaBledy[i]); }
                this.dbf.ListaBledy.Clear();
            }
            MyWidok.setLogNewData(this.ListaBledow, gridLog);
        }

        private string getParametr(string parametr)
        {
            PolaczenieSql p = new PolaczenieSql("SDS02", "skokcom");
            string query = "select wartosc from dbf2sql.parametry where parametr='folder_dbf'";
            string wartosc = "";
            try
                { wartosc =  ((DataTable)(p.Zapytaj(query))).Rows[0][0].ToString(); }
            catch
                { MessageBox.Show("Nie udało się pobrać listy tabel"); }
            p.Rozlacz();
            return wartosc;
        }

        private void getListaTabel()
        {
            PolaczenieSql p = new PolaczenieSql("SDS02","skokcom");
            string query = "select * from dbf2sql.lista_tabel_program order by nazwa";
            try
            {
                this.ListaTabel = p.Zapytaj(query);
                gridListaTabel.DataSource = this.ListaTabel;
                gridListaTabel.Columns[0].Visible = false;
            }
            catch
            {
                MessageBox.Show("Nie udało się pobrać listy tabel");
            }
            p.Rozlacz();
        }


    

        private void btWybierzPlik_Click(object sender, EventArgs e)
        { openFileDialog1.ShowDialog(); }

        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            inputPlik.Text = openFileDialog1.FileName;
            inputNazwaTabeli.Text = Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
        }

        public void WatekProgressu()
        {           
            // czekamy na odczytanie nagłówka aby mieć informację ile jest rekordów
            while (this.dbf.Odczytano_Naglowek == false) { Thread.Sleep(100);}
            // ustawiamy maxy na progressbarach
            Invoke(new Proces(setProgressSettings));
            // pętla odświeżająca dane na formularzu
            while (WriteActive)
            {
                Thread.Sleep(100);
                Invoke(new ProcesInt(RefreshProgress), this.dbf.Odczytano);
            }
            
        }

        private void setProgressSettings()
        {
            MyWidok.setProgresSettings(progressBar1, 0, dbf.LiczbaRekordow);
            MyWidok.setProgresSettings(progressBar2, 0, dbf.LiczbaRekordow);
        }

        private void RefreshProgress(int wartosc)
        {
            TimeSpan sub = DateTime.Now.Subtract(start);
            TimeSpan sub2 = DateTime.Now.Subtract(start_calkowity);
            MyWidok.setProgres(progressBar1, wartosc,lblProcPlik);
            MyWidok.setProgres(progressBar2, zaladowano,lblProcSql);
            MyWidok.setLabelValue(lblOdczytano, wartosc);
            MyWidok.setLabelValue(lblZaladowano, zaladowano);
            MyWidok.setCzasTabeli(lblCzas, sub);
            MyWidok.setCzasCalkowity(lblCzasCalkowity, sub2);
            MyWidok.setZuzyciePamieci(lblPamiec);
            MyWidok.setPredkoscZapisu(lblMB, this.dbf.FileSize, zaladowano, dbf.LiczbaRekordow, sub);
            MyWidok.setLiczbaRekordow(lblLiczbaRek, this.dbf.LiczbaRekordow);
        }


        private void gridLog_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        { groupLog.Text = "Log błędów (" + gridLog.Rows.Count.ToString() + ")"; }


        //Zapisywanie tabeli
        private void button2_Click(object sender, EventArgs e)
        {
            PolaczenieSql s = new PolaczenieSql("SDS02","skokcom");
            SqlDataAdapter ad = new SqlDataAdapter("select * from dbf2sql.lista_tabel_program",s._polaczenie);
            SqlCommandBuilder b = new SqlCommandBuilder(ad);
            ad.Update(this.ListaTabel);
            getListaTabel();
            MessageBox.Show("Dane zostały zapisane.");
        }

        public void setPodswietlTabele(int i)
        { MyWidok.setTableActive(gridListaTabel, i); }

        //Zapisywanie ścieżki domyślnej
        private void button5_Click(object sender, EventArgs e)
        {
            PolaczenieSql p = new PolaczenieSql("SDS02", "skokcom");
            string query = "update dbf2sql.parametry set wartosc='" + inputFolder.Text.ToString() + "' where parametr ='folder_dbf'";
            p.ZapytajVoid(query);
            p.Rozlacz();
            MessageBox.Show("Zapisano ścieżkę jako domyślną");
            p = null;
        }


        private void odswiezListeTabel(object sender, EventArgs e)
        {
            getListaTabel();
        }

        private void btSingleStop_Click(object sender, EventArgs e)
        {

        }

        

        

        

        
    }
}
